//代码题
setTimeout(function () {
    var a = ' hello'
    setTimeout(function () {
        var b = ' lagou'
        setTimeout(function () {
            var c = ' I love U'
            console.log(a +b + c);
        },10)
    },10)
},10)

//1. 使用Promise方法
var promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        var a = ' hello'
        resolve(a)
    },10)
})

promise.then(res => {
   return new Promise((resolve,reject) => {
        setTimeout(() => {
            var b = ' lagou'
            resolve(res + b)
        },10) 
    })
}).then(res => {
    setTimeout(() => {
        var c = ' I love U'
        console.log(res + c);
    },10)  
})


// 二
const fp  =require('lodash/fp')
//数据
//horsepower 马力，dollar_value 价格，in_stock  库存
const cars = [
    {name: 'Ferrari FF', horsepower: 660, dollar_value: 700000, in_stock: true},
    {name: 'Spyker C12 Zagato', horsepower: 650, dollar_value: 648000, in_stock: false},
    {name: 'Jaguar XKR-S', horsepower: 550, dollar_value:132000, in_stock: false},
    {name: 'Audi R8', horsepower: 525, dollar_value:114200, in_stock: false},
    {name: 'Aston Martin One-77', horsepower: 750, dollar_value:1850000, in_stock: true},
    {name: 'Pagani Huayra', horsepower: 700, dollar_value:1300000, in_stock: false}
]

//1.使用函数组合fp.flowRight()重新实现下面这个函数
let isLastInStock = function (cars) {
    //获取最后一条数据
    let last_car = fp.last(cars)
    //获取最后一条数据的in_stock属性值
    return fp.prop('in_stock',last_car)
}
console.log(isLastInStock(cars));

//改写
let isLastInStockFlow = fp.flowRight(fp.prop('in_stock'),fp.last);
console.log(isLastInStockFlow(cars));

//2.使用fp.flowRight(),fp.prop()和fp.first()获取第一个car的name
let isFirstInName = fp.flowRight(fp.prop('name'),fp.first)
console.log(isFirstInName(cars));

//3.使用帮助函数_average重构averageDollarValue，使用函数组合的方式实现
let _average = function (xs) {
    return fp.reduce(fp.add, 0, xs) /xs.length
} //<-无需改动

let averageDollarValue = function (cars) {
    let dollar_values = fp.map(function (car) {
        return car.dollar_value
    }, cars)
    return _average(dollar_values)
}
console.log(averageDollarValue(cars));
//改写
let averageDollarValueCompose = fp.flowRight(_average,fp.map(fp.prop('dollar_value')))
console.log(averageDollarValueCompose(cars));

//4.使用flowRight写一个sanitizeNames()函数，返回一个下划线连接的小写字符串，把数组中的name转换为这种形式：例如：
// sanitizeNames(['Hello World']) => ['hello_world']


let _underscore = fp.replace(/\W+/g,'_') //无需改动，并在sanitizeNames中使用它
let sanitizeNames = fp.flowRight(fp.concat([]),_underscore,fp.toLower)
console.log(sanitizeNames(['Hello World']));

// 三、基于下面提供的代码，完成后续的四个练习

// 1.使用fp.add(x,y)和fp.map(f,x)创建一个能让functor里的值增加的函数ex1

const {Maybe,Container}  = require('./support')
let maybe = Maybe.of([5,6,1]) //返回一个函子

let ex1 = () => {
    return maybe.map(fp.map(fp.add(1)))
}
console.log(ex1());

//2.实现一个函数ex2，能够使用fp.first获取列表的第一个元素
let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la','ti', 'do'])
let ex2 = () => {
    return xs.map(fp.first)
}

console.log(ex2());

//3.实现一个函数ex3,使用safeProp和fp.first找到user的名字的首字母
let safeProp = fp.curry(function (x, o) {
    return Maybe.of(o[x])
})

let user = {id: 2, name: 'Albert' }
let ex3 = (name) => {
    return function (u) {
        return safeProp(name)(u).map(fp.first)
    }
    
}

console.log(ex3('name')(user));

//4.使用Maybe重写ex4，不要有if语句
// let ex4 = function (n) {
//     if (n) {
//         return parseInt(n)
//     }
// }
// console.log(ex4('a2'));


//MayBe函子

class MayBe {
    static of (value) {
        return new MayBe(value)
    }
    constructor (value) {
        this._value = value
    }

    map (fn) {
        return this.isNothing() ? MayBe.of(this._value) : MayBe.of(fn(this._value))
    }
     
    isNothing () {
        return this._value === null || this._value === undefined
    }
}


let ex4 = MayBe.of('3').map(parseInt);
console.log(ex4);

//四、手写实现MyPromise源码要求，尽可能还原Promise中的每一个API，并通过注释的方式描述思路和原理。
//手写实现myPromise

//定义promise状态
const PENDING = 'pending'  //等待状态
const FULFILLED = 'fulfilled'  //成功状态
const REJECTED = 'rejected'   //失败状态

class myPromise {
    //传递一个执行器进去，执行器会立即执行
    constructor (executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
        
    }
    //状态为pending
    status = PENDING;
    //初始化成功的值
    value = undefined;
    //初始化失败的原因
    reason = undefined
    //成功回调函数
    successCallback = []
    //失败回调函数
    failCallback = []
    //resolve 函数
    resolve = (value) =>{
        //当状态不为pending时阻止程序向下执行
        if(this.status !== PENDING) return;
        //执行resolve函数状态变为fulfilled
        this.status = FULFILLED
        //保存成功的值
        this.value = value
        //判断成功回调函数是否存在，若存在则执行成功回调函数
        while(this.successCallback.length) this.successCallback.shift()()
    }

    //reject函数
    reject = (reason) => {
        //当状态不为pending时阻止程序向下执行
        if(this.status !== PENDING) return;
        //执行reject函数状态变为rejected
        this.status = REJECTED
        //保存失败的原因
        this.reason = reason
        ////判断失败回调函数是否存在，若存在则执行失败回调函数
        while(this.failCallback.length) this.failCallback.shift()()
    }

    //then函数
    then = (successCallback, failCallback) => {
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => reason
        const promise2 = new myPromise((resolve,reject) => {
                //当状态为fulfilled时调用成功的回调函数
            if (this.status === FULFILLED) {
                setTimeout(() =>{
                    try {
                        let x = successCallback(this.value)
                        //判断x是普通对象还是promise对象
                        // 普通对象 resolvex(x)
                        //promise对象，查看promise返回的结果，根据返回结果决定调用resolve还是reject
                        resolvePromise(promise2, x, resolve,reject)
                    } catch (error) {
                        reject(error)
                    }
                },0)
            }
            //当状态为rejected时调用失败的回调函数
            else if (this.status === REJECTED) {
                setTimeout(()=>{
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                },0)
            }
            else {
                //保存成功回调函数和失败回调函数
                this.successCallback.push(() => {
                    setTimeout(() =>{
                        try {
                            let x = successCallback(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    },0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    },0)
                })
            }
        })
        //返回promise
        return promise2
        
    }

    //catch函数
    catch = () =>{
        return this.then(undefined,this.failCallback)
    }
    //all方法
    static all (array) {
        let results = []
        let index = 0
        //返回myPromise对象
        return new myPromise((resolve, reject) => {

            // 存储数组数据
            function addData (key,value) {
                results[key] = value
                index++
                //判断传入和保存的数组长度是否相等
                if(index === array.length){
                    resolve(results)
                }
            }
            //遍历数组元素
            for (let i = 0; i < array.length; i++) {
                const element = array[i];
                //element为myPromise对象
                if (element instanceof myPromise) {
                    element.then(value => addData(i, value),reason => reject(reason))
                }
                else {
                    //element为普通值
                    addData(i, array[i])
                }
                
            }
        })
    }

    //race方法
    static race (array) {
        return new myPromise((resolve, reject) => {
            for (let i = 0; i < array.length; i++) {
                if (array[i] instanceof myPromise) {
                    array[i].then(resolve, reject)
                }
                else {
                    resolve(array[i])
                }
            }
        })
    }
    //resolve方法
    static resolve (value) {
        //value为promise对象，直接返回
        if(value instanceof myPromise) return value;
        //value不是promise对象，创建一个新的promise对象，传递一个执行器进去，在执行器中拿到resolve方法，通过resolve方法把value进行返回
        return new myPromise(resolve => resolve(value))
    }

    //finally方法
    finally (callback) {
        //调用then方法
        return this.then(value =>{
            //将callback返回的结果使用myPromise.resolve转化
            return myPromise.resolve(callback()).then(() =>value)
        },reason =>{
            return myPromise.resolve(callback()).then(() => {throw reason})
        })

    }
}


resolvePromise = (promise2, x, resolve, reject) => {
    if(promise2 === x){
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if(x instanceof myPromise){
        // x.then(value => resolve(value), reason => reject(reason))
        x.then(resolve,reject)
    }else {
        resolve(x)
    }
}
module.exports = myPromise